/*
 * @Author: hongbin
 * @Date: 2025-05-02 15:07:41
 * @LastEditors: hongbin
 * @LastEditTime: 2025-05-03 17:21:54
 * @Description: 菲尼尔
 */
import { ThreeHelper } from "@/ThreeHelper";
import * as THREE from "three";

interface IParams {
    threshold?: number;
    transparent?: boolean;
    side?: THREE.Side;
    discard?: boolean;
    solidColor?: THREE.Vector4;
    voidColor?: THREE.Vector4;
}

const defaultParams = {
    threshold: 0.6,
    transparent: true,
    side: THREE.FrontSide,
    discard: true,
    solidColor: new THREE.Vector4(...new THREE.Color(1, 0, 0), 1),
    voidColor: new THREE.Vector4(...new THREE.Color(1, 0, 0), 0.03),
};

export class FresnelMaterial extends THREE.ShaderMaterial {
    constructor(params: IParams = defaultParams) {
        params = { ...defaultParams, ...params };

        super({
            uniforms: {
                cameraPos: { value: new THREE.Vector3(0, 0, 0) },
                solidColor: {
                    value:
                        params.solidColor ||
                        new THREE.Vector4(...new THREE.Color(1, 0, 0), 1),
                },
                voidColor: {
                    value:
                        params.voidColor ||
                        new THREE.Vector4(...new THREE.Color(0, 0, 1), 0.3),
                },
            },
            vertexShader: /* glsl */ `
                 varying vec2 vUv;
                 varying vec3 vViewPosition;
                 varying vec3 vNormal;
                 
                 void main() {
                     vUv = uv;
                     vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
                     gl_Position = projectionMatrix * modelViewPosition;
         
                     vNormal = normalMatrix * normal;
                     
                     vec3 transformed = vec3( position );
         
                     vec4 mvPosition = vec4( transformed, 1.0 );
                     
                     mvPosition = modelViewMatrix * mvPosition;
         
                     vViewPosition = - mvPosition.xyz;
                 }`,
            fragmentShader: /* glsl */ `
                 varying vec2 vUv;
                 varying vec3 vViewPosition;
                 varying vec3 vNormal;
         
                 uniform vec3 cameraPos;
                 uniform vec4 solidColor;
                 uniform vec4 voidColor;
                 
                 void main() {
                     vec3 geometryPosition = - vViewPosition;
         
                     float diff = pow(1.0 - max(dot(normalize(cameraPos - geometryPosition),vNormal), 0.0),1.);

                     // gl_FragColor = vec4(vec3(diff), diff);
                    //  gl_FragColor = vec4(vec3(diff), 1.);
                    //  gl_FragColor = vec4(vec3(intensity), 1.);


                     if(diff > ${params.threshold}){
                        gl_FragColor = solidColor;
                     }else {
                        gl_FragColor = voidColor;
                        ${params.discard ? "discard" : ""};
                    }
                 }`,
            transparent: params.transparent,
            side: params.side,
        });

        this.onBeforeRender = () => {
            const viewMatrix = ThreeHelper.instance.camera.matrixWorldInverse;

            this.uniforms.cameraPos.value.setFromMatrixPosition(
                ThreeHelper.instance.camera.matrixWorld
            );

            this.uniforms.cameraPos.value.applyMatrix4(viewMatrix);
        };
    }
}
